package main

import (
	"encoding/json"
	"fmt"
)

// json Marshal: 将数据编码成json字符串

type Stu struct {
	Name  string `json:"name"`
	Age   int
	High  bool
	sex   string
	Class *Class `json:"class"`
}

type StuInterface struct {
	Name  interface{} `json:"name"`
	Age   interface{}
	High  interface{}
	sex   interface{}
	Class interface{} `json:"class"`
}

type Class struct {
	Name  string
	Grade int
}

func main() {

	// 实例化一个数据结构，用于生成json字符串
	//stu := Stu{
	//	Name: "张三",
	//	Age:  18,
	//	High: true,
	//	sex:  "男",
	//}

	stu := StuInterface{
		Name: "张三",
		Age:  18,
		High: true,
		sex:  "男",
	}

	// 指针变量
	cla := new(Class)
	cla.Name = "1班"
	cla.Grade = 3

	stu.Class = cla

	// Marshal失败时err != nil
	jsonStu, err := json.Marshal(stu)
	if err != nil {
		fmt.Println("生成json字符串报错")
	}

	// jsonStu是一个[]byte类型，转换成string类型易于查看
	// 打印结果没有sex，因为sex首字母小写，不可导出
	fmt.Println(string(jsonStu))

	// 从结果中可以看出:
	//
	// 只要是可导出成员（变量首字母大写），都可以转成json。因成员变量sex是不可导出的，故无法转成json。
	// 如果变量打上了json标签，如Name旁边的 json:"name" ，那么转化成的json key就用该标签“name”，否则取变量名作为key，如“Age”，“HIgh”。
	// bool类型也是可以直接转换为json的value值。Channel， complex 以及函数不能被编码json字符串。当然，循环的数据结构也不行，它会导致marshal陷入死循环。
	// 指针变量，编码时自动转换为它所指向的值，如cla变量。
	// （当然，不传指针，Stu struct的成员Class如果换成Class struct类型，效果也是一模一样的。只不过指针更快，且能节省内存空间。）
	// 最后，强调一句：json编码成字符串后就是纯粹的字符串了。

	// 上面的成员变量都是已知的类型，只能接收指定的类型，比如string类型的Name只能赋值string类型的数据。
	// 但有时为了通用性，或使代码简洁，我们希望有一种类型可以接受各种类型的数据，并进行json编码。这就用到了interface{}类型。
}
